#[allow(dead_code)]
#[derive(Debug)]
struct Value {
    v : String,
}
impl Value {
    #[allow(dead_code)]
    fn new() -> Self {
        Self {
            v: "hello".to_owned()
        }
    }
}

trait Bak {
    fn haha(self);
}
impl<'a> Bak for &'a mut Value {
    fn haha(self) {
        println!("Bak-for: {:?}", *self);
    }
}


#[allow(dead_code)]
fn mut_func(v: &mut Value) {
    v.haha();
}
/*compile error 
fn func(v: & Value) {
    v.haha();
}
*/







#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test(){
        {
            let mut v = Value::new();
            let mut_ref_v = &mut v;
            mut_func(mut_ref_v);
            mut_func(mut_ref_v);
        }
       /* 
        {
            let v = Value::new();
            func(&v);
        }
        */
    }

    //IMMutable struct (&mut ref) 
    //  1. Use RefCell
    use std::cell::RefCell;
    trait Pushable {
        fn push_once(self, c: char); //DoOnce Semantic
        fn push_more(self, c: char) -> Self; //DoManyTimes Semantic
    }
    #[test]
    fn imm_contains_mut_use_refcell() {
        struct Serializer<'a> {
            output: RefCell<&'a mut String>,
        }


        impl<'a> Serializer<'a> {
            fn new(s: &'a mut String) -> Self{
                Self {
                    output: RefCell::new(s),
                }
            }
        }

        // this is the target use
        impl<'a> Pushable for Serializer<'a>{
            fn push_once(self, c: char) {
                self.output.borrow_mut().push(c);
            }
            fn push_more(self, c: char) -> Self{
                self.output.borrow_mut().push(c);
                self
            }
        }

        let mut result = String::new();
        let ser = Serializer::new(&mut result);
        ser.push_more('h').push_once('c');
    }


    //IMMutable struct (&mut ref) 
    //  1. Use impl for &'a mut T 
    #[test]
    fn imm_contains_mut_high_performance(){
        struct Serializer {
            output: String ,
        }

        impl Serializer {
            fn new() -> Self {
                Self {
                    output: String::new()
                }
            }
        }

        impl<'a> Pushable for &'a mut Serializer {
            fn push_once(self, c: char){
                self.output.push(c);
            }
            fn push_more(self, c: char) -> Self{
                self.output.push(c);
                self
            }
        }

        let mut ser = Serializer::new();
        (&mut ser).push_more('h'); //push_more(self, move the &'a mut Serial
        (&mut ser).push_more('h'); //push_more(self, move the &'a mut Serial

        (&mut ser).push_once('c');
        println!("{}", ser.output);
    }
    
}

